From 80e5f07b5277fc5f526ebf6d83e161bd635dfa3e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 30 Oct 2005 10:45:49 +0100 Subject: [PATCH] Fix floating-point corruption (a nasty race in fp task-switch exception handling). Signed-off-by: Keir Fraser --- .../arch/xen/i386/kernel/entry.S | 2 +- .../arch/xen/i386/kernel/traps.c | 23 ++++++++++++------- xen/arch/x86/traps.c | 22 ++++++++++++++---- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S b/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S index 24c2d5a5fe..d4ac275630 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S @@ -653,7 +653,7 @@ ENTRY(simd_coprocessor_error) ENTRY(device_not_available) pushl $-1 # mark this as an int SAVE_ALL - preempt_stop + #preempt_stop /* This is already an interrupt gate on Xen. */ call math_state_restore jmp ret_from_exception diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/traps.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/traps.c index 81f701b8a4..5a22809760 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/traps.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/traps.c @@ -648,6 +648,12 @@ fastcall void do_int3(struct pt_regs *regs, long error_code) } #endif +static inline void conditional_sti(struct pt_regs *regs) +{ + if ((uint8_t)(regs->xcs >> 16) == 0) + local_irq_enable(); +} + /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore @@ -680,11 +686,9 @@ fastcall void do_debug(struct pt_regs * regs, long error_code) if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, SIGTRAP) == NOTIFY_STOP) return; -#if 0 + /* It's safe to allow irq's after DR6 has been saved */ - if (regs->eflags & X86_EFLAGS_IF) - local_irq_enable(); -#endif + conditional_sti(regs); /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { @@ -967,15 +971,18 @@ void __init trap_init_f00f_bug(void) #endif -/* NB. All these are "trap gates" (i.e. events_mask isn't cleared). */ +/* + * NB. All these are "trap gates" (i.e. events_mask isn't cleared) except + * for those that specify |4 in the second field. + */ static trap_info_t trap_table[] = { { 0, 0, __KERNEL_CS, (unsigned long)divide_error }, - { 1, 0, __KERNEL_CS, (unsigned long)debug }, - { 3, 3, __KERNEL_CS, (unsigned long)int3 }, + { 1, 0|4, __KERNEL_CS, (unsigned long)debug }, + { 3, 3|4, __KERNEL_CS, (unsigned long)int3 }, { 4, 3, __KERNEL_CS, (unsigned long)overflow }, { 5, 3, __KERNEL_CS, (unsigned long)bounds }, { 6, 0, __KERNEL_CS, (unsigned long)invalid_op }, - { 7, 0, __KERNEL_CS, (unsigned long)device_not_available }, + { 7, 0|4, __KERNEL_CS, (unsigned long)device_not_available }, { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun }, { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS }, { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present }, diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 44f902f505..df278750fd 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1147,6 +1147,9 @@ asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason) asmlinkage int math_state_restore(struct cpu_user_regs *regs) { + struct trap_bounce *tb; + trap_info_t *ti; + /* Prevent recursion. */ clts(); @@ -1154,10 +1157,15 @@ asmlinkage int math_state_restore(struct cpu_user_regs *regs) if ( current->arch.guest_context.ctrlreg[0] & X86_CR0_TS ) { - struct trap_bounce *tb = ¤t->arch.trap_bounce; + tb = ¤t->arch.trap_bounce; + ti = ¤t->arch.guest_context.trap_ctxt[TRAP_no_device]; + tb->flags = TBF_EXCEPTION; - tb->cs = current->arch.guest_context.trap_ctxt[7].cs; - tb->eip = current->arch.guest_context.trap_ctxt[7].address; + tb->cs = ti->cs; + tb->eip = ti->address; + if ( TI_GET_IF(ti) ) + tb->flags |= TBF_INTERRUPT; + current->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS; } @@ -1169,6 +1177,7 @@ asmlinkage int do_debug(struct cpu_user_regs *regs) unsigned long condition; struct vcpu *v = current; struct trap_bounce *tb = &v->arch.trap_bounce; + trap_info_t *ti; __asm__ __volatile__("mov %%db6,%0" : "=r" (condition)); @@ -1198,9 +1207,12 @@ asmlinkage int do_debug(struct cpu_user_regs *regs) /* Save debug status register where guest OS can peek at it */ v->arch.guest_context.debugreg[6] = condition; + ti = &v->arch.guest_context.trap_ctxt[TRAP_debug]; tb->flags = TBF_EXCEPTION; - tb->cs = v->arch.guest_context.trap_ctxt[TRAP_debug].cs; - tb->eip = v->arch.guest_context.trap_ctxt[TRAP_debug].address; + tb->cs = ti->cs; + tb->eip = ti->address; + if ( TI_GET_IF(ti) ) + tb->flags |= TBF_INTERRUPT; out: return EXCRET_not_a_fault; -- 2.30.2